package com.euond.accv.gateway.filter;

import com.euond.accv.gateway.constant.FilterConstants;
import com.euond.accv.gateway.domain.CustomerDevAuthorization;
import com.euond.accv.gateway.service.CustomerDevAuthorizationService;
import com.euond.accv.gateway.utils.Utils;
import com.euond.common.domain.search.Searchable;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 验证请求路径安全性，安全性按照ant path配置模式判断
 *
 * http://blog.csdn.net/chenqipc/article/details/53289721
 *
 * 对请求进行拦截与过滤
 * filterOrder:filter执行顺序，通过数字指定 
   shouldFilter:filter是否需要执行 true执行 false 不执行 
    run : filter具体逻辑 
	filterType :filter类型,分为以下几种
 */
public class UrlPathFilter extends ZuulFilter {
	private final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 客户资源限缓存前缀
	 */
	protected static final String REDIS_CUSTOMER_DEV_AUTHORIZATION="redis_customer_dev_authorization_";
	/**
	 * 有效期为两小时
	 */
	protected static final int EXPIRE_TIME = 2 * 60 * 60;


	@Autowired
	RedisTemplate redisTemplate;

	@Autowired
	private CustomerDevAuthorizationService service;

	/**
	 * 是否执行run方法
	 */
	@Override
	public boolean shouldFilter() {
		String retCode = (String)RequestContext.getCurrentContext().get("retCode");
		if(StringUtils.isNotBlank(retCode) && retCode.equals("0")) {
			return true;
		}
		return false;
	}

	@Override
	public Object run() {
		logger.info("run UrlPath Filter.....");

		RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String reqUrl = request.getRequestURI();
		Map<String,String> map = (Map<String,String>)ctx.get(FilterConstants.RESULT);


		String customerNo = map.get("customerNo");
		List<Map<String,String>> list = getCustomerDevAuthorizations(customerNo);
		if(list != null && list.size() > 0){
			boolean authSuccess = false;
			AntPathMatcher antPathMatcher = new AntPathMatcher();
			for(Map<String,String> auth : list){
				boolean bl = antPathMatcher.match(auth.get("url"),reqUrl);
				if(bl){
					authSuccess = true;
					break;
				}
			}

			if(authSuccess == false){
				String resultStr = Utils.resultJson("1040","授权失败,[url:"+reqUrl+"]不允许访问!");
				ctx.setResponseBody(resultStr);
				ctx.setSendZuulResponse(false);
				ctx.set(FilterConstants.STATUS_CODE,"1040");
				return null;
			}

			ctx.set(FilterConstants.STATUS_CODE,"0");
			return null;

		}else{
			String resultStr = Utils.resultJson("1030","授权失败,[url:"+reqUrl+"]不允许访问!");
			ctx.setResponseBody(resultStr);
			ctx.setSendZuulResponse(false);
			ctx.set(FilterConstants.STATUS_CODE,"1030");
			return null;
		}
	}


	/**
	 * 获取客户资源权限,先从缓存取，如果缓存没有则数据库取
	 *
	 * @param customerNo 客户编号
	 * @return
	 */
	public List<Map<String,String>> getCustomerDevAuthorizations(String customerNo){
		String key = REDIS_CUSTOMER_DEV_AUTHORIZATION + customerNo;
		List<Map<String,String>> authorizationList = (List<Map<String,String>>)redisTemplate.opsForValue().get(key);
		if(authorizationList == null){
			Searchable searchable = Searchable.newSearchable();
			searchable.addSearchParam("customerNo_eq",customerNo);
			searchable.addSearchParam("status_eq","1");
			List<CustomerDevAuthorization> list = service.findAll(searchable).getContent();
			if(list.size() > 0) {
				authorizationList = new ArrayList<>();
				for(CustomerDevAuthorization customer:list){
					Map<String,String> map = new HashMap<>();
					map.put("customerNo",customer.getCustomerNo());
					map.put("serverName",customer.getServerName());
					map.put("url",customer.getUrl());
					map.put("id",customer.getId()+"");
					authorizationList.add(map);
				}

				redisTemplate.opsForValue().set(key, authorizationList, EXPIRE_TIME, TimeUnit.SECONDS);
			}
		}
		return authorizationList;
	}

	/**
	 * 	pre:请求执行之前filter 
		route: 处理请求，进行路由 
		post: 请求处理完成后执行的filter 
		error:出现错误时执行的filter
	 */
	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

	@Override
	public int filterOrder() {
		return 30;
	}

}
